#include "cvt.h"
#include "cvt_cls.h"
#include <stdarg.h>
#include "sscvt_win/cvt_win_export.h"

#define STRSAFE_MAX_CCH     2147483647

_SSL_BEGIN
_SSBASEL_BEGIN

auto_cvt::auto_cvt(const char *p, bool copy_ori_string /* = false */)
{
	init(p, copy_ori_string);
}

auto_cvt::auto_cvt(const std::string &str, bool copy_ori_string /*= false*/)
{
	init(str.c_str(), copy_ori_string);
}

auto_cvt::auto_cvt(const wchar_t *p, bool copy_ori_string /* = false */)
{
	init(p, copy_ori_string);
}

auto_cvt::auto_cvt(const std::wstring &str, bool copy_ori_string /*= false*/)
{
	init(str.c_str(), copy_ori_string);
}

auto_cvt::auto_cvt(const auto_cvt& other)
{
	int_from_other(other);
}

auto_cvt::~auto_cvt()
{
	uninit();
}

auto_cvt& auto_cvt::operator = (const auto_cvt &rhs)
{
	uninit();
	int_from_other(rhs);
	return *this;
}

const char *auto_cvt::c_astr()
{
	if(ori_string_ansi != 0)
		return ori_string_ansi;
	return astr();
}

const wchar_t *auto_cvt::c_wstr()
{
	if(ori_string_u16 != 0)
		return ori_string_u16;
	return wstr();
}

const char *auto_cvt::c_utf8str()
{
	if(ori_string_utf8 != 0)
		return ori_string_utf8;
	return utf8str();
}

#ifdef UNICODE
const wchar_t *auto_cvt::c_tstr()
{
	return c_wstr();
}
#else
const char *auto_cvt::c_tstr()
{
	return c_astr();
}
#endif

char *auto_cvt::astr()
{
	if(string_ansi != 0) return string_ansi;

	if(ori_string_ansi != 0)
		string_ansi = cvt_a2a(ori_string_ansi);
	else if(ori_string_u16 != 0)
		string_ansi = cvt_w2a(ori_string_u16);
	else if(ori_string_utf8 != 0)
		string_ansi = cvt_ue2a(ori_string_utf8);

	return string_ansi;
}

wchar_t *auto_cvt::wstr()
{
	if(string_u16 != 0) return string_u16;

	if(ori_string_ansi != 0)
		string_u16 = cvt_a2w(ori_string_ansi);
	else if(ori_string_u16 != 0)
		string_u16 = cvt_w2w(ori_string_u16);
	else if(ori_string_utf8 != 0)
		string_u16 = cvt_ue2w(ori_string_utf8);

	return string_u16;
}

char *auto_cvt::utf8str()
{
	if(string_utf8 != 0) return string_utf8;

	if(ori_string_ansi != 0)
		string_utf8 = cvt_a2ue(ori_string_ansi);
	else if(ori_string_u16 != 0)
		string_utf8 = cvt_w2ue(ori_string_u16);
	else if(ori_string_utf8 != 0)
		string_utf8 = cvt_ue2ue(ori_string_utf8);

	return string_utf8;
}

#ifdef UNICODE
const wchar_t *auto_cvt::tstr()
{
	return wstr();
}
#else
const char *auto_cvt::tstr()
{
	return astr();
}
#endif

void auto_cvt::init(const char *p, bool copy_ori_string)
{
	ori_string_ansi = 0;
	ori_string_utf8 = 0;
	ori_string_u16 = 0;
	string_ansi = 0;
	string_utf8 = 0;
	string_u16 = 0;

	if(cvt_checkutf8(p))
	{
		if(copy_ori_string)
		{
			string_utf8 = cvt_ue2ue(p);
			ori_string_utf8 = string_utf8;
		}else
		{
			ori_string_utf8 = p;
			if(ori_string_utf8 == NULL)
				ori_string_utf8 = "";
		}
	}else
	{
		ori_string_ansi = p;
		if(copy_ori_string)
		{
			string_ansi = cvt_a2a(p);
			ori_string_ansi = string_ansi;
		}else
		{
			ori_string_ansi = p;
			if(ori_string_ansi == NULL)
				ori_string_ansi = "";
		}
	}
}

void auto_cvt::init(const wchar_t *p, bool copy_ori_string)
{
	ori_string_ansi = 0;
	ori_string_utf8 = 0;
	ori_string_u16 = 0;
	string_ansi = 0;
	string_utf8 = 0;
	string_u16 = 0;

	if(copy_ori_string)
	{
		string_u16 = cvt_w2w(p);
		ori_string_u16 = string_u16;
	}else
	{
		ori_string_u16 = p;
		if(ori_string_u16 == NULL)
			ori_string_u16 = L"";
	}
}

void auto_cvt::int_from_other(const auto_cvt &rhs)
{
	ori_string_ansi = 0;
	ori_string_utf8 = 0;
	ori_string_u16 = 0;
	string_ansi = NULL;
	string_u16 = NULL;
	string_utf8 = NULL;

	ori_string_ansi = rhs.ori_string_ansi;
	ori_string_u16 = rhs.ori_string_u16;
	ori_string_utf8 = rhs.ori_string_utf8;

	if(rhs.string_ansi != NULL)
	{
		string_ansi = cvt_a2a(rhs.string_ansi);
	}

	if(rhs.ori_string_u16 != NULL)
	{
		string_u16 = cvt_w2w(rhs.ori_string_u16);
	}

	if(rhs.string_utf8 != NULL)
	{
		string_utf8 = cvt_ue2ue(rhs.string_utf8);
	}
}

void auto_cvt::uninit()
{
	ori_string_ansi = 0;
	ori_string_utf8 = 0;
	ori_string_u16 = 0;

	if(string_ansi != 0)
	{
		cvt_free(string_ansi);
		string_ansi = 0;
	}

	if(string_utf8 != 0)
	{
		cvt_free(string_utf8);
		string_utf8 = 0;
	}

	if(string_u16 != 0)
	{
		cvt_free(string_u16);
		string_u16 = 0;
	}
}

auto_cvt auto_cvt::from_fmt(const char *p, ...)
{
	if(p == NULL)
	{
		return auto_cvt("");
	}

	size_t buffer_size = strlen(p) * 2 + 1;
	ss_auto_buffer<char> buffer;

	va_list vl;
	va_start(vl, p);

	while(true)
	{
		int ret = win_v_printf_a(buffer.alloc_ptr(buffer_size),
			buffer_size, p, vl);
		if(ret == 1)
		{
			if(buffer_size >= STRSAFE_MAX_CCH)
				break;
			if(buffer_size * 2 >= STRSAFE_MAX_CCH)
				buffer_size = STRSAFE_MAX_CCH;
			else
				buffer_size *= 2;
			continue;
		}

		if(ret == 0)
		{
			va_end(vl);
			return auto_cvt(buffer.ptr(), true);
		}
		break;
	}

	va_end(vl);

	return auto_cvt("");
}

auto_cvt auto_cvt::from_fmt(const wchar_t *p, ...)
{
	if(p == NULL)
	{
		return auto_cvt(L"");
	}

	size_t buffer_size = wcslen(p) * 2 + 1;
	ss_auto_buffer<wchar_t> buffer;

	va_list vl;
	va_start(vl, p);

	while(true)
	{
		int ret = win_v_printf_w(buffer.alloc_ptr(buffer_size),
			buffer_size, p, vl);
		if(ret == 1)
		{
			if(buffer_size >= STRSAFE_MAX_CCH)
				break;
			if(buffer_size * 2 >= STRSAFE_MAX_CCH)
				buffer_size = STRSAFE_MAX_CCH;
			else
				buffer_size *= 2;
			continue;
		}

		if(ret == 0)
		{
			va_end(vl);
			return auto_cvt(buffer.ptr(), true);
		}
		break;
	}

	va_end(vl);

	return auto_cvt(L"");
}

_SSBASEL_END
_SSL_END

